/**
 * fichier PFP de AMD du 21 janvier 2009
 * @author amd
 * Preemptive Fixed Priority
 * see <a href="{@docRoot}/Documentation/scheduler.html"> for more information</a>
 * 20/01
 * Copyright (c) 2009 Ecole Centrale de Nantes IRCCyN
 */
 
package storm.Schedulers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

import storm.EvtContext;
import storm.Processors.Processor;
import storm.Tasks.Task;


public class FP_P_Scheduler extends Scheduler {
	/**
	 * 
	 * @author amd
	 *
	 */
	class LReady extends ArrayList implements Comparator {
		/**
		 * 
		 */
		public int compare(Object arg0, Object arg1) {
			Task T0 = (Task) arg0;
			Task T1 = (Task) arg1;
			if (T0.priority > T1.priority) return -1;
			else if (T0.priority == T1.priority) return 0;
			     else return 1;
		}
	}
	/**
	 * 
	 */
	private LReady list_ready;
	private Boolean todo = false;
	/**
	 * 
	 */
	public void init() {
		list_ready = new LReady();
	}
	/**
	 * 
	 */
	public void onActivate(EvtContext c) {
		list_ready.add(c.getCible());
		/**
		 * reordonnancement necessaire
		 */
		todo = true;
	}
	/**
	 * 
	 */
	public void onUnBlock(EvtContext c){
		list_ready.add(c.getSource());
		//System.out.println(this.Kernel.getTime() + "  BLOCK  "  + list_ready.size());
		


		/**
		 * reordonnancement necessaire
		 */
		todo = true;
	}
	/**
	 * 
	 */
	public void onBlock(EvtContext c){
		Task T = (Task) c.getCible();
		/*if (list_ready.size()==2)
		System.out.println(this.Kernel.getTime() + "  BLOCK  "  + list_ready.size() + "  " + list_ready.get(0)+ list_ready.get(1));
*/
		list_ready.remove(c.getCible());

		/**
		 * reordonnancement necessaire uniquement si cette tache quitte l'etat Running
		 */
		


		if (T.predStateIsRunning()) todo = true;
		
	}
	/**
	 * 
	 */
	public void onTerminated(EvtContext c){
		list_ready.remove(c.getCible());
		/**
		 * reordonnancement necessaire
		 */
		todo = true;
	}
	/**
	 * 
	 */
	public void sched(){
	
		if (todo) {
			select();
			todo = false;
		}
	}
	/**
	 * 
	 */
	public void select() {
		/**
		 * tri de la liste des taches pretes
		 */
		Collections.sort(list_ready,list_ready);
		ArrayList CPUS =this.Kernel.getTasksListeManager().getProcessors();
		int m = CPUS.size();	// m = nb processeurs 
		/**
		 * les m (au +) taches les + prios sont en tete de la liste
		 * les suivantes doivent etre si necessaire preemptees
		 */
		for (int i=m; i<list_ready.size(); i++){
			Task T = (Task) list_ready.get(i);
			if (T.isIsrunning()) T.preempt();
		}
		/**
		 * construction de la liste des processeurs actuellement libres
		 */
		ArrayList freeProcList = new ArrayList();
		Iterator iCPU = CPUS.iterator();
		while (iCPU.hasNext()) {
			Processor p = (Processor) iCPU.next();
			if (!p.isRunning()) {
				freeProcList.add(p);
			}
		}
		/**
		 * on affecte si possible a chacun des processeurs libres une tache parmi les + prios
		 * sans changer l'affectation des taches deja Running
		 */
		int j = 0;
		for (int i=0; (j<freeProcList.size()) && (i<list_ready.size()); i++){
			Task T = (Task) list_ready.get(i);
			if (!T.isIsrunning()) {
				Processor P = (Processor) freeProcList.get(j);
				T.runningOn(P);
				j++;
			}
		}
	}

}
